import { HtmlResize } from '@logicflow/extension';
import { EdgeConfig, GraphConfigData, h, type NodeData } from "@logicflow/core"
import { GroupNode } from '@logicflow/extension';
import VueNode from "./LoopHtml.vue"
import { ref, type App, createApp, h as H } from 'vue';

interface Bounds {
    x1: number,
    y1: number,
    x2: number,
    y2: number,
}

const headerHeight = 90;
const boxWidth = 150;

const startBound: Bounds = {
    x1: 0,
    y1: 0,
    x2: boxWidth,
    y2: headerHeight
}

const breakBound: Bounds = {
    x1: boxWidth,
    y1: 0,
    x2: boxWidth * 2,
    y2: headerHeight
}

// enum loopType {
//     FOR_NODE, FOR_NUM, WHILE, ITERATOR
// }

class WhenGroup extends HtmlResize.view {
    appRef = ref(null as any);
    node: HTMLDivElement;

    constructor(props: any) {
        super(props);
        const app = createApp({
            render: () => H(VueNode, {
                ref: this.appRef, callback: (properties) => {
                    props.model.setProperties(properties)
                },
                properties: props.model.getProperties()
            })
        });
        this.node = document.createElement("div");
        this.node.style.boxSizing = "border-box"
        this.node.style.height = "100%"
        app.mount(this.node);
    }

    setHtml(rootEl: HTMLElement): void {
        rootEl.appendChild(this.node);
    }

    getControlGroup() {
        const { resizable, properties } = this.props.model;
        return resizable && !properties.isFolded ? super.getControlGroup() : h("rect", {});
    }

    getFoldIcon() {
        const { model } = this.props;
        const foldX = model.x - model.width / 2 + 5;
        const foldY = model.y - model.height / 2 + 5;
        if (!model.foldable) return null;

        const iconIcon = h('path', {
            fill: 'none',
            stroke: '#818281',
            strokeWidth: 2,
            'pointer-events': 'none',
            d: model.properties.isFolded
                ? `M ${foldX + 3},${foldY + 6} ${foldX + 11},${foldY + 6} M${foldX + 7},${foldY + 2} ${foldX + 7},${foldY + 10}`
                : `M ${foldX + 3},${foldY + 6} ${foldX + 11},${foldY + 6} `,
        });
        return h('g',
            {},
            [
                h('rect', {
                    height: 12,
                    width: 14,
                    rx: 2,
                    ry: 2,
                    strokeWidth: 1,
                    fill: '#F4F5F6',
                    stroke: '#CECECE',
                    cursor: 'pointer',
                    x: model.x - model.width / 2 + 5,
                    y: model.y - model.height / 2 + 5,
                    onClick: () => {
                        model.foldGroup(!model.properties.isFolded);
                    },
                }),
                iconIcon,
            ]);
    }

    getResizeShape() {
        const { properties } = this.props.model;
        this.appRef.value?.fold(properties.isFolded);
        return h('g', {}, [
            super.getResizeShape(),
            this.getFoldIcon(),
        ]);
    }
}


class WhenGroupModel extends GroupNode.model {
    getNodeStyle() {
        const style = super.getNodeStyle();
        style.stroke = '#AEAFAE';
        style.strokeDasharray = '3 3';
        style.strokeWidth = 1;
        return style;
    }

    getAnchorStyle(anchorInfo: any) {
        const style = super.getAnchorStyle(anchorInfo);
        style.stroke = '#000';
        style.fill = '#fff';
        style.hover.fill = '#aaa';
        style.hover.stroke = '#eee';
        return style;
    }

    initNodeData(data: any) {
        super.initNodeData(data);

        this.isRestrict = true;
        this.foldable = true;
        this.resizable = true;
        this.foldedWidth = 90;
        this.foldedHeight = 60;
        this.width = 500;
        this.height = 300;
        if (this.isFolded) {
            setTimeout(() => {
                this.foldGroup(true);
            });
            this.isFolded = false;
        }
    }

    foldGroup(isFolded: any) {
        super.foldGroup(isFolded);
        this.setAttributes();
    }

    //重构，解决折叠时边样式问题,虽然比较丑陋，但还是解决了
    createVirtualEdge(edgeData: EdgeConfig) {
        edgeData.pointsList = undefined;
        const end = this.graphModel.getNodeModelById(edgeData.targetNodeId);
        edgeData.endPoint = {
            x: end.x - end.width / 2,
            y: end.y
        }
        const start = this.graphModel.getNodeModelById(edgeData.sourceNodeId);
        edgeData.startPoint = {
            x: start.x + start.width / 2,
            y: start.y
        }

        const model = this.graphModel.addEdge(edgeData);
        model.virtual = true;
        // 强制不保存group连线数据
        // model.getData = () => null;
        model.text.editable = false;
        model.isFoldedEdge = true;
    }

    setAttributes() {
        //用异步可以获取最新的宽高。。。
        this.anchorsOffset = [
            [this.width / 2, 0],
            [0, this.height / 2],
            [-this.width / 2, 0],
            [0, -this.height / 2],
        ]
    }

    isInRange({ x1, y1, x2, y2 }: Bounds) {
        //   if (x1 < (this.x - this.width / 2)) return false;
        //   if (x2 > (this.x + this.width / 2)) return false;
        //   if (y1 < (this.y - this.height / 2)) return false;
        //   if (y2 > (this.y + this.height / 2)) return false;
        const isChild = x1 >= (this.x - this.width / 2)
            && x2 <= (this.x + this.width / 2)
            && y1 >= (this.y - this.height / 2 + headerHeight)
            && y2 <= (this.y + this.height / 2);

        const isBreak = this.isBreak({ x1, y1, x2, y2 });
        const isStart = this.isStart({ x1, y1, x2, y2 });

        return isChild || isBreak || isStart;
    }

    //覆盖默认的移动规则，使用isAllowMoveToTest重写，在FlowView中显式添加
    isAllowMoveTo(b: Bounds) {
        return {
            x: true,
            y: true
        };
    }

    isBreak({ x1, y1, x2, y2 }: Bounds) {
        return x1 >= (this.x - this.width / 2 + breakBound.x1)
            && x2 <= (this.x - this.width / 2 + breakBound.x2)
            && y1 >= (this.y - this.height / 2 + breakBound.y1)
            && y2 <= (this.y - this.height / 2 + breakBound.y2);
    }

    isStart({ x1, y1, x2, y2 }: Bounds) {
        return x1 >= (this.x - this.width / 2 + startBound.x1)
            && x2 <= (this.x - this.width / 2 + startBound.x2)
            && y1 >= (this.y - this.height / 2 + startBound.y1)
            && y2 <= (this.y - this.height / 2 + startBound.y2);
    }

    isAllowMoveToTest({ x1, y1, x2, y2 }: Bounds, old: Bounds) {
        const isBreak = this.isBreak(old);
        if (isBreak) {
            return {
                x: x1 >= (this.x - this.width / 2 + breakBound.x1) && x2 <= (this.x - this.width / 2 + breakBound.x2),
                y: y1 >= (this.y - this.height / 2 + breakBound.y1) && y2 <= (this.y - this.height / 2 + breakBound.y2),
            }
        }
        const isStart = this.isStart(old);
        if (isStart) {
            return {
                x: x1 >= (this.x - this.width / 2 + startBound.x1) && x2 <= (this.x - this.width / 2 + startBound.x2),
                y: y1 >= (this.y - this.height / 2 + startBound.y1) && y2 <= (this.y - this.height / 2 + startBound.y2),
            }
        }
        return {
            x: x1 >= (this.x - this.width / 2) && x2 <= (this.x + this.width / 2),
            y: y1 >= (this.y - this.height / 2 + headerHeight) && y2 <= (this.y + this.height / 2),
        }
    }

    //children直接换成flowdata
    getData(): NodeData {
        const properties = this.getProperties()
        const data: NodeData = super.getData();
        const flowData: GraphConfigData = { nodes: [], edges: [] };
        //选出start和break节点
        data.children.forEach((childId: string) => {
            const model = this.graphModel.getNodeModelById(childId);
            const bounds = model.getBounds();
            if (this.isStart(bounds)) {
                if (data.startId) throw new Error("循环只有单个start");
                data.startId = childId;
                return;
            }
            if (this.isBreak(bounds)) {
                if (data.breakId) throw new Error("循环只有单个break");
                data.breakId = childId;
                return;
            }

            flowData.nodes.push(model.getData());
            flowData.edges.push(...model.incoming.edges.map(edge => edge.getData()));
        });

        data.flowData = flowData
        data.properties = properties
        //保存折叠之前的宽高
        if (properties.isFolded) {
            data.x = this.x + this.unfoldedWidth / 2 - this.foldedWidth / 2;
            data.y = this.y + this.unfoldedHight / 2 - this.foldedHeight / 2;
        }
        return data;
    }
}

export default {
    type: "LOOP",
    view: WhenGroup,
    model: WhenGroupModel
};
